package cau.se.project.view;

import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.wb.swt.SWTResourceManager;

import cau.se.project.data.method.RowControl;
import cau.se.project.method.CLSXControl;
import cau.se.project.view.method.DSMChangeListener;
import de.kupzog.ktable.KTable;
import de.kupzog.ktable.KTableCellSelectionAdapter;

public class DSMTableView extends Composite {

	private DSMTableModel tableModel = new DSMTableModel();
	private CLSXControl clsx = null;
	private List<RowControl> arrayList = null;
    private KTable table = new KTable(this, SWT.H_SCROLL | SWT.V_SCROLL);
    private Point pCellSelected = null;
    
    private boolean doNotMove;			// 셀 이동을 하지 않게 하는 특수 주건
    private boolean bMouseDown = false;
	private DSMChangeListener dsmChangeListener = null;

	public DSMTableView(Composite parent, int style) {
		super(parent, style);
	    table.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
	    table.setPreferredSizeDefaultRowHeight(1);
	    table.setNumRowsVisibleInPreferredSize(10);
	    table.setNumColsVisibleInPreferredSize(10);
	    table.setModel(tableModel);

	    // mouse events
	    setMouseOperations();
	    
	    // layout
	    FillLayout layout = new FillLayout();
	    setLayout(layout);
	}
	
	public void select(int index)
	{
		table.setSelection(0, index+1, true);
	}
	
	public int getRowCount()
	{
		return table.getSize().x-1;
	}
	
	public int getSelectedIndex()
	{
		Point[] p = table.getCellSelection();
		if(p.length == 0)
			return -1;
		return p[0].y-1;
	}
	
	public void refresh(CLSXControl clsx, List<RowControl> list)
	{
		this.clsx = clsx;
		this.arrayList = list;
		this.pCellSelected = null;
		
		tableModel.setData(list);
		
		System.out.println("refresh");
		table.setRedraw(false);		
		table.resizeColumnOptimal(0);
		refresh();
		table.setRedraw(true);
	}
	
	private void refresh()
	{
		table.redraw(0, 0, tableModel.getColumnCount(), tableModel.getRowCount());
	}
	
	private void setMouseOperations()
	{
		// 셀이 선택되었을 때 이벤트
		table.addCellSelectionListener(new KTableCellSelectionAdapter() {
			
			boolean doNotRepeat = false;
			@Override
			public void cellSelected(int col, int row, int statemask) {
				super.cellSelected(col, row, statemask);
				
				if(col != 0 || doNotRepeat) return;
				
				RowControl selected = arrayList.get(row-1);
				doNotRepeat = true;
				emitSelectionChanged(selected);
				doNotRepeat = false;
			}
		});
		
	    table.addMouseListener(new MouseListener() {
			
			@Override
			public void mouseUp(MouseEvent e) {
				bMouseDown = false;
				Point p = table.getCellForCoordinates(e.x, e.y);

				// 특별 외곽선 없애기
				tableModel.setCellSpceialBorder(null);
				
				//
				if(p.y == 0) {
					return;
				}
				
				if(pCellSelected != null && p.x == 0 && doNotMove == false) {
					
					// calculate destination
					int rowDest = p.y - 1;
					
					RowControl rcFrom = arrayList.get(pCellSelected.y-1);
					RowControl rcTo = arrayList.get(rowDest);
					
					// 자기자신 이동은 하지 않음
					if(rcFrom == rcTo)
						return;
					
					System.out.println(String.format("move row %d to %d", pCellSelected.y-1, rowDest));
					try {
						if(rcFrom.getParent() != rcTo.getParent())
							throw new Exception("부모가 같은 노드끼리만 이동이 가능합니다");
						clsx.moveRowTo(rcFrom, rcTo, true);
						emitCLSXChanged();
					} catch (Exception e1) {
						MessageBox msgbox = new MessageBox(getShell());
						msgbox.setMessage(e1.getMessage());
						msgbox.open();
						e1.printStackTrace();
					}
				}
			}
			
			@Override
			public void mouseDown(MouseEvent e) {
				bMouseDown = true;
				
				Point[] pCell = table.getCellSelection();
				Point positionCell = table.getCellForCoordinates(e.x, e.y);
				if(pCell.length == 0)
					return;
				
				// for test
				if(pCell[0].equals(positionCell)) {
					System.out.println("same");
					doNotMove = false;
				}
				else {
					System.out.println("different");
					doNotMove = true;
				}
				
				//
				if(pCell[0].x != 0) {
					pCellSelected = null;
					System.out.println("disselect");
					emitSelectionChanged(null);
				}
				else {
					pCellSelected = pCell[0];
					System.out.println(String.format("select header %d", pCell[0].y));
				}
			}
			
			@Override
			public void mouseDoubleClick(MouseEvent e) {
				Point p = table.getCellForCoordinates(e.x, e.y);
				if(p.x == 0 || p.y == 0 || p.x == p.y)
					return;
				
				try {
					tableModel.setContentAt(p.x, p.y, !(boolean)tableModel.getContentAt(p.x, p.y));
				} catch (Exception e1) {
					MessageBox msg = new MessageBox(getShell());
					msg.setMessage(e1.getMessage());
					msg.open();
					return;
				}
				emitDSMChanged();
				refresh();
			}
		});
	    table.addMouseMoveListener(new MouseMoveListener() {
			
			@Override
			public void mouseMove(MouseEvent e) {
				if(bMouseDown == false)
					return;
				
				System.out.println("move detected");
				if(pCellSelected == null)
					return;
				
				Point cellCurrentOn = table.getCellForCoordinates(e.x, e.y);
				Point cellPrevOn = tableModel.getCellSpceialBorder();
				if(cellCurrentOn.equals(cellPrevOn))
					return;
				
				if(cellCurrentOn.y != 0) {
					System.out.println("set Special");
					tableModel.setCellSpceialBorder(new Point(0, cellCurrentOn.y));
					table.redraw(0, 0, 1, tableModel.getRowCount());
				}
			}
		});
	}

	private void emitDSMChanged()
	{
		if(dsmChangeListener != null)
			dsmChangeListener.onDSMChanged();
	}
	
	private void emitCLSXChanged()
	{
		if(dsmChangeListener != null)
			dsmChangeListener.onCLSXChanged();
	}
	private void emitSelectionChanged(RowControl row)
	{
		if(dsmChangeListener != null)
			dsmChangeListener.onSelectionChanged(row);
	}

	public void setOnDSMChangeListener(DSMChangeListener l)
	{
		this.dsmChangeListener = l;
	}
	
	public void setShowLabel(boolean bShowLabel)
	{
		tableModel.setShowName(bShowLabel);
	}
	
	@Override
	public void addKeyListener(KeyListener arg0) {
		table.addKeyListener(arg0);
		super.addKeyListener(arg0);
	}
}
